#include "gps_track.h"

#define TRACK_DEF_LINE_WIDTH 3

GPS_track::GPS_track() :
    Modifiable()
{
    static int track_id = 0;
    _line_width = TRACK_DEF_LINE_WIDTH;
    _title = _description = "";
    _totalLength = 0;
    _totalPoints = 0;
    _id = track_id++;
}

GPS_track::~GPS_track()
{
    foreach ( GPS_waypoint* wp, _waypoints )
        delete wp;
    foreach ( GPS_leg* lg, _legs )
        delete lg;
}

QList<int> GPS_track::listWaypoints() const
{
    return _waypoints.keys();
}

const GPS_waypoint* GPS_track::waypoint(int id) const
{
    if ( _waypoints.contains( id ) )
        return _waypoints.value(id);
    return NULL;
}

GPS_waypoint* GPS_track::waypointMod(int id)
{
    if ( _waypoints.contains( id ) )
        return _waypoints.value(id);
    return NULL;
}

void GPS_track::clearTrack()
{
    _boundingRect = QRect();
    _legs.clear();
    _waypoints.clear();
    _title = "";
    _description = "";
    _totalLength = 0;
    _totalPoints = 0;
}

void GPS_track::waypointUpdated( GPS_waypoint *nwp)
{
    int id = nwp->id();
    if ( !_waypoints.contains( id ) )
        addWaypoint( nwp );
    else
    {
        Modify();
        expandBoundingRect( nwp->latitude(), nwp->longitude() );
    }
}

void GPS_track::expandBoundingRect(double lat, double lon)
{
    if ( _boundingRect.isEmpty() )
    {
        if ( _boundingRect.bottomLeft().isNull() )
            _boundingRect.setBottomLeft( QPointF( lon, lat ) );
        else
        {
            _boundingRect.setTopRight( QPointF( lon, lat ) );
            _boundingRect = _boundingRect.normalized();
        }
    }
    else
    {
        if ( lon < _boundingRect.left() )
            _boundingRect.setLeft( lon );
        if ( lat < _boundingRect.top() )
            _boundingRect.setTop( lat );
        if ( lon > _boundingRect.right() )
            _boundingRect.setRight( lon );
        if ( lat > _boundingRect.bottom() )
            _boundingRect.setBottom( lat );
    }
}
void GPS_track::deleteWaypoint( int id )
{
    if ( _waypoints.contains( id ) )
    {
        Modify();
        delete _waypoints.take( id );
    }
}

QList<int> GPS_track::listLegs() const
{
    return _legs.keys();
}

const GPS_leg* GPS_track::leg(int id) const
{
    if ( _legs.contains( id ) )
        return _legs.value(id);
    return NULL;
}

GPS_leg* GPS_track::legMod(int id)
{
    if ( _legs.contains( id ) )
        return _legs.value(id);
    return NULL;
}

void GPS_track::legUpdated( GPS_leg *nlg)
{
    int id = nlg->id();
    if ( !_legs.contains( id ) )
        addLeg( nlg );
    else
    {
        Modify();
       _boundingRect = _boundingRect.united( nlg->boundingRect() );
    }
}

void GPS_track::deleteLeg( int id)
{
    if ( _legs.contains( id ) )
    {
        Modify();
        GPS_leg* delLeg = _legs.take( id );
        _totalLength -= delLeg->lengthMt();
        _totalPoints -= delLeg->nPoints();
        delete delLeg;
    }
}


int GPS_track::lineWidth() const
{
    return _line_width;
}

void GPS_track::setLineWidth(int lw)
{
    if ( lw != _line_width )
    {
        Modify();
        _line_width = lw;
    }
}

QString GPS_track::title() const
{
    return _title;
}

void GPS_track::setTitle(const QString& t)
{
    if ( t != _title )
    {
        Modify();
        _title = t;
    }
}

QString GPS_track::description() const
{
    return _description;
}

void GPS_track::setDescription(const QString& d)
{
    if ( d != _description )
    {
        Modify();
        _description = d;
    }
}

QRectF GPS_track::boundingRect() const
{
    return _boundingRect;
}

void GPS_track::setBoundingRect(const QRectF& rc)
{
    if ( rc != _boundingRect )
    {
        Modify();
        _boundingRect = rc;
    }
}

void GPS_track::addLeg(GPS_leg* nlg )
{
    int id = nlg->id();
    if ( !_legs.contains(id) )
    {
        Modify();
        _legs.insert( id, nlg );
        _totalLength += nlg->lengthMt();
        _totalPoints += nlg->nPoints();
        _boundingRect = _boundingRect.united( nlg->boundingRect() );
    }
}

int GPS_track::nLegs() const
{
    return _legs.count();
}

void GPS_track::dropLastPointFromLeg(int leg_id)
{
    if ( _legs.contains( leg_id ) )
    {
        _totalLength -= _legs[ leg_id ]->lengthMt();
        _legs[ leg_id ]->removeLastPoint();
        _totalPoints -= 1;
        _totalLength += _legs[ leg_id ]->lengthMt();
    }
}

bool GPS_track::addPointToLeg(GPS_point* pt, int leg_id)
{
    if ( _legs.contains( leg_id ) )
    {
        _totalLength -= _legs[ leg_id ]->lengthMt();
        _legs[ leg_id ]->addPoint( pt );
        _totalPoints += 1;
        _totalLength += _legs[ leg_id ]->lengthMt();
        expandBoundingRect( pt->latitude(), pt->longitude() );
        return true;
    }
    return false;
}

void GPS_track::addWaypoint(GPS_waypoint* nwp)
{
    int id = nwp->id();
    if ( !_waypoints.contains(id) )
    {
        Modify();
        _waypoints.insert( id, nwp );
        expandBoundingRect( nwp->latitude(), nwp->longitude() );
    }
}

int GPS_track::totalLength() const
{
    return _totalLength;
}

int GPS_track::totalPoints() const
{
    return _totalPoints;
}

int GPS_track::id() const
{
    return _id;
}
